#include <sys/select.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <arpa/inet.h>

#include "tklog.h"
#include "tkconstants.h"
#include "tknetutils.h"
#include "tkevent.h"

#define CUSTOM_SOCKET_TYPE_DEFAULT	0
#define CUSTOM_SOCKET_TYPE_LISTEN	1

struct custom_event {
	void *data;			/* point to custom_socket */

	unsigned int type;
	struct custom_event *next;

	/**
        struct rb_node node;
	unsigned long timeout_time;
	**/
	
	/* kinds of flag */
        unsigned accept_ready:1;
	unsigned readable_flag:1;
        unsigned writable_flag:1;
        unsigned active:1;      	/* register in event pool, active will be 1, and or not */
	unsigned active_read:1;
	unsigned active_write:1;
	unsigned active_error:1;
        unsigned timeout:1;     	/* if the event is timeout set 1 */
        unsigned in_timer_set:1;        /* if the event is set in timer, in_timer_set flag will be 1 */
        unsigned shutdown:1;            /* aready close status, now wait for connection's other side's read or write */
        unsigned error:1;

};

void set_after_connect(struct select_env *env, after_connect_entry after_connect)
{
	env->after_connect = after_connect;
}

void* get_custom_event(void *data)
{
	void *p = malloc(sizeof(struct custom_event));
	struct custom_event *event = (struct custom_event*)p;
	memset(event, 0x00, sizeof(struct custom_event));
	
	event->data = data;

	return p;
}

struct custom_socket* get_custom_socket(int sockfd)
{
	struct custom_socket* s = (struct custom_socket*)malloc(sizeof(struct custom_socket));
	if (!s)
		return NULL;

	memset(s, 0x00, sizeof(struct custom_socket));
	s->event = get_custom_event(s);
	if (s->event) {
		free(s);
		return NULL;
	}
	memset(s->event, 0x00, sizeof(struct custom_event));
	
	s->sockfd = sockfd;

	return s;	
}

void destory_custom_socket(struct select_env *env, struct custom_socket *s)
{
	if (s == NULL)
		return;

	struct custom_event *event = (struct custom_event*)s->event;

	if (s->sockfd > 0) {
		select_del_rw_event(env, event);
		close(s->sockfd);
	}
		
	if (s->event) {
		free(s->event);
		s->event = NULL;
	}
	if (s)
		free(s);
}

int is_accept(void *pv)
{
	struct custom_event* event = (struct custom_event*)pv;
	return (event->accept_ready == 1);
} 

int is_writable(void *pv)
{
        struct custom_event* event = (struct custom_event*)pv;
        return (event->writable_flag == 1);	
}

int is_readable(void *pv)
{
	struct custom_event* event = (struct custom_event*)pv;
        return (event->readable_flag == 1);
}

void set_readable(void *pv, int flag)
{
	struct custom_event* event = (struct custom_event*)pv;
	event->readable_flag = flag;
}

void set_writable(void *pv, int flag)
{
	struct custom_event *event = (struct custom_event*)pv;
	event->writable_flag = flag;
}

int is_active(void *pv) 
{
	struct custom_event* event = (struct custom_event*)pv;
        return (event->active == 1);
}

int is_timeout(void *pv) 
{
	struct custom_event* event = (struct custom_event*)pv;
        return (event->timeout == 1);
}

int is_intimerset(void *pv)
{
	struct custom_event* event = (struct custom_event*)pv;
        return (event->in_timer_set == 1);
}

int is_shutdown(void *pv)
{
        struct custom_event* event = (struct custom_event*)pv;
        return (event->shutdown == 1);
}

int is_error(void *pv)
{
        struct custom_event* event = (struct custom_event*)pv;
        return (event->error == 1);
}

void set_event_type(void *pv, int type) 
{
        struct custom_event* event = (struct custom_event*)pv;
	event->type = type;
}

void set_event_data(void *pv, void *data)
{
        struct custom_event* event = (struct custom_event*)pv;
	event->data = data;
}
void* get_event_data(void *pv)
{
        struct custom_event* event = (struct custom_event*)pv;
	return event->data;
}

/* 设置毫秒数 */
void set_select_env_timeout(struct select_env *env, int millseconds)
{
	env->timeout.tv_sec = millseconds / 1000;
	env->timeout.tv_usec = (millseconds - millseconds/ 1000 * 1000) * 1000;
}

struct select_env* create_select_env(after_connect_entry after_connect)
{
	int len = 0;
	int epollfd;
	struct select_env *env = NULL;

	env = (struct select_env*)malloc(sizeof(struct select_env));
	if (!env)
		return NULL;

	memset(env, 0x00, sizeof(sizeof(struct select_env));
	set_select_env_timeout(env, 100);

        return env;
	
}

int destory_select_env(struct select_env *env)
{
	if (env == NULL)
		return 0;

	free(env);
	
	return 0;
}

/* always return 0 */
int select_add_event(struct select_env *env, void *event, int event_type)
{
	struct select_event	ee;
	struct custom_event	*ev = NULL;	/* input event */
	struct custom_socket 	*s = NULL;
	int events = 0;
	int op = 0;
	int i;
	int availScoketIndex = -1;

	if ((ev->active_write && ev->active_read && ev->active_error) || event_type = 0)
		return 0;

	if (ev->active == 0) {
		for (i = 0; i < MAX_SELECT_FD; i++) {
			if (env->sockets_map[i] < 0) {
				availScoketIndex = i;
				break;
			}
		}
		if (i == MAX_SELECT_FD) {
			return -1;
		}
	}

	ev = (struct custom_event*)event;
	s = (struct custom_socket*)ev->data;

	ev->active = 1;
	if (events & EVENT_READ) {
		FD_SET(s->sockfd, &env->readfds);
		ev->active_read = 1;
	}
	if (events & EVENT_WRITE)  {
		ev->active_write = 1;
		FD_SET(s->sockfd, &env->writefds);
	}
	if (events & EVENT_ERROR) {
		ev->active_error = 1;
		FD_SET(s->sockfd, &env->errorfds);
	}

	if (availScoketIndex != -1) {
		ev->sockets_map[availScoketIndex] = s->sockfd;
		ev->sockets[availScoketIndex] = event;	
	}
	
	return 0;
}

int select_del_event(struct select_env *env, void *event, int event_type)
{
	struct select_event	ee;
	struct custom_event	*ev = NULL;	/* input event */
	struct custom_socket	*s = NULL;
	int events = 0;
	int op = 0;
	int i;

	s = ev->data;
	ev = (struct custom_event*)event;
	if (ev->active == 0 || event_type == 0) 
		return 0;

	if (ev->active_read && (event_type & EVENT_READ)) {
		ev->active_read = 0;
		FD_CLR(s->sockfd, &env->readfds);
	}

	if (ev->active_write && (event_type & EVENT_WRITE)) {
		ev->active_write = 0;
		FD_CLR(s->sockfd, &env->writefds);
	}
	
	if (ev->active_error && (event_type & EVENT_ERROR)) {
		ev->active_error = 0;
		FD_CLR(s->sockfd, &env->errorfds);
	}

	if (ev->active_read == 0 && ev->active_write == 0 && ev->active_error == 0) {
		ev->active = 0;
		for (i = 0; i < MAX_SELECT_FD) {
			if (event == env->sockets[i]) {
				env->sockets[i] = NULL;
				env->sockets_map[i] = -1;
				break;
			}
		}
	}
	
	return 0;
}

int select_add_read_event(struct select_env *env, void *event)
{
	return select_add_event(env, event, EVENT_READ);
}

int select_add_write_event(struct select_env *env, void *event)
{
	return select_add_event(env, event, EVENT_WRITE);
}

int select_add_error_event(struct select_env *env, void *event)
{
	return select_add_event(env, event, EVENT_ERROR);
}

int select_del_read_event(struct select_env *env, void *event)
{
	return select_del_event(env, event, EVENT_READ);
}

int select_del_write_event(struct select_env *env, void *event)
{
	return select_del_event(env, event, EVENT_WRITE);
}

int select_del_error_event(struct select_env *env, void *event)
{
	return select_del_event(env, event, EVENT_ERROR);
}

int select_del_rw_event(struct select_env *env, void *event)
{
	return select_del_event(env, event, EVENT_READ | EVENT_WRITE);
}

int select_add_rw_event(struct select_env *env, void *event)
{
	return select_del_event(env, event, EVENT_READ | EVENT_WRITE);
}

int select_process_events(struct select_env* env, int nfds, long timeout)
{
	int r;
	int events_num;
	struct custom_socket *s = NULL;
	struct custom_event *ev = NULL;
	int i;
	int events;
	int fd;

	env->timeout.tv_sec = timeout / 1000;
	env->timeout.tv_usec = (timeout - env->timeout.tv_sec * 1000) * 1000;
	
	memset(&env->readfds, 0x00, sizeof(env->readfds));
	memset(&env->writefds, 0x00, sizeof(env->writefds));
	memset(&env->errorfds, 0x00, sizeof(env->errorfds));
	r = events_num = select(nfds, &env->readfds, &env->writefds, &env->errorfds, &env->timeout); 
        if (r == -1) {
                if (r == EINTR) {
			elog("epoll wait eintr");
                        return 0;
		}
                else {
			elog("epoll wait failed, errno[%d]", errno);
                        return -1;
		}
        }
	else if (r == 0) {
		ilog("timeout");
	}
	else {
		/* only one socket */
		for (i = 0; i < MAX_SELECT_FD; i++) {
			events = 0;
			if (env->sockets_map[i] > 0) {
				if (FD_ISSET(env->sockets_map[i], &env->readfds) {
					events |= EVENT_READ;
				}	
				if (FD_ISSET(env->sockets_map[i], &env->writefds) {
					events |= EVENT_WRITE;
				}	
				if (FD_ISSET(env->sockets_map[i], &env->errorfds) {
					events |= EVENT_ERROR;
				}	

				ev = (struct custom_event*)env->sockets[i];
				s = (struct custom_socket*)ev->data;
					
				if (events & EVENT_ERROR)) {
					if (!s->handler) 
						ilog("ip[%s]-port[%d] event's handler is null", s->addr.ipv4, s->addr.port);
					else
						(VOID)hd_handler_entry(env, s, EVENT_LOCAL_ERROR);
					elog("client ip[%s] port[%d] occur error when connected", s->addr.ipv4, s->addr.port);
					ev->error = 1;
				} 
				else {
					if (!s->handler) 
						ilog("ip[%s]-port[%d] event's handler is null", s->addr.ipv4, s->addr.port);
					else 
						(VOID)hd_handler_entry(env, s, EVENT_REMOTE_CLOSE);
					elog("client ip[%s] port[%d] occur error closed", s->addr.ipv4, s->addr.port);
				}

				/* error process */
				if (ev->error == 1) {
				}
				else if (ev->finished == 1)
			}
		}
	}

	return events_num;
}

void tk_socket_error(struct select_env *env, struct custom_socket *s)
{
	destory_custom_socket(env, s);
}
